/*
##author :rubin
##@greenorbs
##Telosb with co2 module COZIR 7711 and 7804
##work mode
##start->startdone->read->readdone->stop->stopdone
*/
//2011-4-12 fix some bug
//when you start to call co2sensor.read(),you will get the data per 6second 
//if you want to start the overtime detect ,you just start timer0 in co2sensor.read();
//init when the co2data can not return in 30 seconds ,the program will signal err

//testco2 with the co2 module GZIR 7711  
//flower is the code about the co2
//2011-12-26  rubin add control pin to switch on and off the co2 module
//###############2012-5-28 co2 module must use by the step start->startdone->read->readdone->stop->stopdone
//test cozir 7804
//study from COZIR Software User's Guide.pdf
//co2 ģ��ʵ��ռ�����ߵ�ʱ������500ms��Ԥ��Ϊ10s ���ο��ֲᣩ
//����ģʽ1 Ԥ�������1S��������ݰ�
//2012-5-29
//test in testnetwork
#include "pr.h"
#include "Timer.h"
#include "UART0MSG.h"
#define WARM_UP_PERIOD (10*1024UL)   // Ԥ��ʱ��
module co2sensorP {
    provides interface Read<uint16_t > as co2sensor ;
    provides interface SplitControl as co2Control;
    provides interface co2Info;
	uses 
    {
	interface Resource as uart0resource;  //testresource ok
    interface HplMsp430Usart as Usart;
    interface HplMsp430UsartInterrupts as Interrupts;
	interface HplMsp430GeneralIO as P20;
    interface Timer<TMilli> as Timer0;
	interface Timer<TMilli> as Timer1;
    //interface MyLeds as Leds;;
	// config interrupt to adjust the sensor
      /*
        interface GpioInterrupt as AdjustSensor;
        interface GeneralIO as P27;
      */
    }
}

implementation 
{
  MSP430REG_NORACE(U0CTL);
  //uint8_t serialcommand[8] = {0xff,0xff,0xfe,0x02,0x02,0x03,0x76,0x05};  //��ȡ�������
  //��ݸ�ʽ
  //10S ��Ԥ��
	uint8_t recdata[MAX_DATA]; //������ݴ洢 10
	norace uint8_t nreading = 0; //���ռ���
	uint8_t i = 0;
	uint16_t co2data = 0;
	bool isStart = FALSE;
	bool flag_set_co2 = FALSE;
	uint8_t Kmode0[COMMAND_DATA_SUM] = {0x4B,0x20,0x30,0x30,0x30,0x30,0x30,0x0d,0x0a};  //Mode0 command K 00000  start mode
	//mode 1 and mode 2 their comsumption is the sanm 
	uint8_t Kmode1[COMMAND_DATA_SUM] = {0x4B,0x20,0x30,0x30,0x30,0x30,0x31,0x0d,0x0a};  //Mode1 command K 00001  streaming mode
	uint8_t Kmode2[COMMAND_DATA_SUM] = {0x4B,0x20,0x30,0x30,0x30,0x30,0x32,0x0d,0x0a};  //Mode2 command K 00002  polling mode 
	//set some data out put //however did not pass test ????????????????????????
	uint8_t MGetCo2Data[MCOMMAND_DATA_SUM] = {0x4D,0x20,0x30,0x30,0x30,0x30,0x36,0x0d,0x0a};  //send command M 6  to get the Z #####z##### out from the sensor which Z mings
	//set x 450\r\n to set the co2 mode
	uint8_t ZToZeroCo2[ZCOMMAND_DATA_SUM] = {0x58,0x20,0x34,0x35,0x30,0x0d,0x0a};//zero command
	uint32_t co2OnInstant = 0;
	uint32_t co2OnTime = 0;
	norace uint16_t noDataTime = 0;
	norace uint16_t resultco2 = 0;
	norace error_t stateCo2 = FAIL;
	bool isInUart0 = FALSE;
    task void recvTask();

	//uart0���ڳ�ʼ������
	msp430_uart_union_config_t config1 = {
		{utxe : 1, 
		 urxe : 1, 
		 ubr : UBR_1MHZ_9600, //Baud rate (use enum msp430_uart_rate_t for predefined rates)
		 umctl : UMCTL_1MHZ_9600, //Modulation (use enum msp430_uart_rate_t for predefined rates)
		 ssel : 0x02,        //Clock source (00=UCLKI; 01=ACLK; 10=SMCLK; 11=SMCLK)
		 pena : 0,           //Parity enable (0=disabled; 1=enabled)
		 pev : 0,            //Parity select (0=odd; 1=even)
		 spb : 0,            //Stop bits (0=one stop bit; 1=two stop bits)
		 clen : 1,           //Character length (0=7-bit data; 1=8-bit data)
		 listen : 0,         //Listen enable (0=disabled; 1=enabled, feed tx back to receiver)
		 mm : 0,             //Multiprocessor mode (0=idle-line protocol; 1=address-bit protocol)
		 ckpl : 0,            //Clock polarity (0=normal; 1=inverted)
		 urxse : 0,           //Receive  -edge detection (0=disabled; 1=enabled)
		 urxeie : 0,          //Erroneous-character receive (0=rejected; 1=recieved and URXIFGx set)
		 urxwie : 0,          //Wake-up interrupt-enable (0=all characters set URXIFGx; 1=only address sets URXIFGx)     
		 utxe : 1,            // 1:enable tx module
		 urxe : 1             // 1:enable rx module
		}
    };

	//command_send to send the command to set the co2 mode 
	void command_send(uint8_t len,uint8_t* ptr)
	{
		for(i = 0; i < len; i++)
		{
			call Usart.tx( *ptr++ ); 
			while( !call Usart.isTxEmpty() );
		}   
    }

	//tx done not used 
	async event void Interrupts.txDone()
	{
	}
	// config the interrupt to adjust the sensor
        /*async event void AdjustSensor.fired()
	{
		call Leds.led1Toggle();
  		call Leds.led2Toggle(); 		
		command_send(ZCOMMAND_DATA_SUM,ZToZeroCo2);
		return ;
	}*/

	//co2 module start 
	//1:set p20 output and on 
	//2:record the start time used to calc co2Ontime
	//4:set a warm up time  
	//3:return success 
	command error_t co2Control.start()
	{
		
		isStart = TRUE;
		call P20.selectIOFunc();//p2.0 IO mode
		call P20.makeOutput();//p2.0 output
		call P20.set();//p2.0 output high
		call Timer1.startOneShot(WARM_UP_PERIOD);
        co2OnInstant = call Timer1.getNow();
		//pr("call co2 start\n");
		return SUCCESS;
	}

	//when warm up time fired ,we can signal the co2 is started
    event void Timer1.fired()
    {
		signal co2Control.startDone(SUCCESS);//warm up time fired 
    }

	//stop the co2 module 
	//1:clr the p20
	//2:release the bus of usart0 so the radio can use the module
	//3:get the co2Ontime
	command error_t co2Control.stop()
	{
		
		call P20.clr();//p2.0 output low
		nreading = 0;
		noDataTime = 0;
	    	isStart = FALSE;
		// command_send(COMMAND_DATA_SUM,Kmode0); //set mode0 to low the comsumption
		
		co2OnTime = ( call Timer1.getNow() - co2OnInstant );
		
	    signal co2Control.stopDone(SUCCESS);
        return SUCCESS;	
	}
	
 	command error_t co2sensor.read()
	{
		if(isStart == FALSE)
			return EBUSY;
        else
        {	
			call Timer0.startPeriodic(1024UL);  //������ʱ�ж�
			call uart0resource.request();
			nreading = 0;
        }
		return SUCCESS;
	}

	// when the overtime is fired ,we can signal the state of co2 mode is fail
	event void Timer0.fired() 
    { 
		//pr("timer0 fired \n");
		noDataTime++;
		if( noDataTime >= MAX_NODATA_TIME)
		{
			// call P20.clr();//p2.0 output low 
			nreading = 0;
			noDataTime = 0;
			isStart = FALSE;
			stateCo2 = FAIL;
			post recvTask();
		}
    }

	//set the mode of usart0 and send the mode1 to co2 module 
	event void uart0resource.granted()
	{
		 // You are now in control of the resource.
		//pr("resource2: %d(%d,%d)\n",(call uart0resource.isOwner()),(call Usart.isSpi()),(call Usart.isUart()) );
		//call Usart.resetUsart(0);
		call Usart.setModeUart(&config1);  //��ʼ������
		call Usart.enableUart();     //�����շ�ʹ��
		call Usart.enableRxIntr();   //�����ж�ʹ��
		U0CTL &= ~SYNC;      //UART0��ʼ��ΪUARTģʽ 	
		//pr("resource3: %d(%d,%d)\n",(call uart0resource.isOwner()),(call Usart.isSpi()),(call Usart.isUart()) );
		isInUart0 = TRUE;

		//ע��Ҫ�趨һ��ʱ�����һ��У׼
		//set the flash air 450ppm
		//send command to set the mode 1 ref_COZIR Software User's Guide.pdf
		//command_send(COMMAND_DATA_SUM,Kmode1);
		//command_send(MCOMMAND_DATA_SUM,MGetCo2Data);
		//set the flash air 450ppm
		if(flag_set_co2 == TRUE)
		{
			command_send(ZCOMMAND_DATA_SUM,ZToZeroCo2);
			flag_set_co2 = FALSE;
		}
	}
	
	
	
	//test the per seconds two packets 
	bool canrecord = FALSE;
	//�жϽ����¼�ʹ�øýӿڵ�ʱ��һ��Ҫע��dissemination�ĸ��� radio
    async event void Interrupts.rxDone(uint8_t data)
    {
		if((call Usart.isUart()) == 1 )
		{
			//pr("uart data :%c ",data);
		if (data == 0x5a) //find Z
		{ 
			//record the data and sum the data 
			canrecord = TRUE;
		}
		if(canrecord == TRUE )
		{
			if(nreading < MAX_DATA)
			{
				recdata[nreading] = data;
			}	
			nreading ++;
			//pr("%c\n",data);
		}
		if(nreading == MAX_DATA)
		{             
			nreading = 0;
			
			//match the syc data
			if((recdata[0] == 0x5a) && (recdata[1] == 0x20) )	
			{
				//get the co2 data 
				co2data =  (recdata[2] & 0x0F)*10000;
				co2data += (recdata[3] & 0x0F)*1000;
				co2data += (recdata[4] & 0x0F)*100;
				co2data += (recdata[5] & 0x0F)*10;
				co2data += (recdata[6] & 0x0F)*1;
				//overtime state clean 
				//call Timer0.stop();
				noDataTime = 0;
				//call Usart.disableRxIntr();
				stateCo2 = SUCCESS;
				resultco2 = co2data;
				post recvTask();
			}
			else
			{
				stateCo2 = FAIL;
				//clean the overtime detect
				//call Timer0.stop();
				noDataTime = 0;
				//call Usart.disableRxIntr();
				post recvTask();
				//signal co2sensor.readDone(FAIL,0xFFFF);
			}
			canrecord = FALSE;
		}
		}
		
	}
	
  uint8_t testtaski =0;	
  task void recvTask()
  {
	if (stateCo2 == FAIL)
	{
		signal co2sensor.readDone(stateCo2,0xFFFF);
		
		// call uart0resource.release();   // must release the bus
	}
	else
	{
		signal co2sensor.readDone(stateCo2,resultco2);
		co2OnTime = (call Timer1.getNow() - co2OnInstant);
		// call uart0resource.release();   // must release the bus
	}
	call Timer0.stop();
	call uart0resource.release(); //must release the bus 
	isInUart0 = FALSE;
	//pr("resource5: %d(%d,%d)\n",(call uart0resource.isOwner()),(call Usart.isSpi()),(call Usart.isUart()) );
	call Usart.disableUart(); 
  }
  command uint32_t co2Info.getCo2OnTime()
  {
    return co2OnTime;

  }
  command error_t co2Info.setCo2sensor()
  {
  	flag_set_co2 = TRUE;	
  	return SUCCESS;	
  }
  

}

